using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Text;
using Autodesk.Revit.UI;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Newtonsoft.Json;
using RevitCopilot.Models;
using RevitCopilot.Config.Options;

namespace RevitCopilot.Services;
//请求：{jsonrpc: "2.0",id: number | string,method: string,params?: object}
//响应：{jsonrpc: "2.0",id: number | string,result?: object,error?: {code: number,message: string,data?: unknown}}
//通知：单向消息{jsonrpc: "2.0";method: string;params?: {[key: string]: unknown;};}

// Socket服务类，用于接收来自MCPServer客户端的请求，解析方法名，并通过ExecCommandService执行对应方法
public class SocketService
{
    private readonly SocketSettings _settings;
    private readonly ILogger<SocketService> _logger;
    private readonly ExternalEvent _externalEvent;
    private readonly ExecCommandService _execCommandService;
    private Socket? _serverSocket;
    private bool _isRunning;

    // 获取服务器运行状态
    public bool IsRunning => _isRunning;
    // 存储客户端Socket的字典，键为请求ID
    private readonly Dictionary<string, Socket> _clientSockets = new Dictionary<string, Socket>();
    public SocketService(IOptions<SocketSettings> options, ILogger<SocketService> logger,
        ExecCommandService execCommandService)
    {
        _settings = options.Value;
        _logger = logger;
        _execCommandService = execCommandService;
        _externalEvent = ExternalEvent.Create(execCommandService);
        _isRunning = false;
        // 订阅命令执行完成事件(发送执行结果消息给MCP请求服务)
        _execCommandService.CommandExecuted += OnCommandExecuted;
    }
    // 启动Socket服务，监听客户端连接
    public void Start()
    {
        if (_isRunning)
        {
            _logger.LogWarning("Socket服务已经在运行中");
            return;
        }
        try
        {
            //IPAddress.Any监听任意端口。127.0.0.1表示只允许本地客户端可以连接
            //IP 地址 + 端口号
            var endPoint = _settings.GetEndPoint();
            // 字节流+TCP协议，监听所有可用的IPV4网络接口
            _serverSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
            // Socket绑定到本地的一个IP 地址和端口，使其可以监听或发送数据，主要用于服务器端
            // connect用于客户端向服务器发起连接请求（仅用于TCP，UDP是无连接的）
            _serverSocket.Bind(endPoint);
            // 挂起连接队列的最大长度
            _serverSocket.Listen(_settings.Backlog);
            // 设置超时
            _serverSocket.ReceiveTimeout = _settings.ReceiveTimeoutMs;
            _serverSocket.SendTimeout = _settings.SendTimeoutMs;
            _logger.LogInformation("Socket 启动成功，监听 {EndPoint}", endPoint);
            _isRunning = true;
            // 在新线程中接受连接，避免阻塞主线程
            Task.Run(() => AcceptConnections());
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Socket 启动失败");
            throw;
        }
    }
    //接受端连接并处理请求
    private void AcceptConnections()
    {
        while (_isRunning && _serverSocket != null)
        {
            try
            {
                // 接受客户端连接，Accept返回一个新的 Socket，专门用于和这个客户端通信
                Socket clientSocket = _serverSocket.Accept();
                // 客户端和服务端在同一台机器时，客户端需要指定服务端地址：127.0.0.1进行连接
                EndPoint clientEndPoint = clientSocket.RemoteEndPoint; // 获取客户端地址
                _logger.LogInformation("客户端连接来自: {ClientEndPoint}", clientEndPoint);
                // 在新线程中处理客户端请求，避免阻塞接受连接的线程
                Task.Run(() => HandleClientRequest(clientSocket));
            }
            catch (SocketException ex) when (ex.SocketErrorCode == SocketError.TimedOut)
            {
                _logger.LogWarning("接受连接超时");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "接受连接失败");
            }
        }
    }
    ///【3】处理客户端请求
    private void HandleClientRequest(Socket clientSocket)
    {
        try
        {
            // 移除using语句块，避免clientSocket被提前释放
            //先接收数据长度，再接收实际数据，int类型是4字节里面存储了数据长度
            byte[] lengthBytes = new byte[4];
            clientSocket.Receive(lengthBytes);
            //字节转换为int类型，得到实际数据的长度，根据长度接收实际数据
            int dataLength = BitConverter.ToInt32(lengthBytes, 0);
            //根据dataLength分配缓冲区，用于存储实际数据
            byte[] requestData = new byte[dataLength];
            int receivedLength = 0;
            //循环接收数据，直到接收完整（Socket.Receive可能不会一次性返回所有数据）
            while (receivedLength < dataLength)
            {
                receivedLength += clientSocket.Receive(requestData, receivedLength, dataLength - receivedLength, SocketFlags.None);
            }
            string jsonRequest = Encoding.UTF8.GetString(requestData);
            _logger.LogInformation("收到客户端请求: {JsonRequest}", jsonRequest);
            // 解析JSON-RPC请求
            JsonRpcRequest? request = JsonConvert.DeserializeObject<JsonRpcRequest>(jsonRequest);
            if (request is null)
            {
                SendErrorResponse(clientSocket, "0", -32700, "解析请求失败");
                clientSocket.Close(); // 请求解析失败后关闭连接
                return;
            }
            // 处理请求并执行命令
            ProcessRequest(clientSocket, request);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "处理客户端请求失败");
            try
            {
                // 发生异常时尝试关闭连接
                if (clientSocket != null && clientSocket.Connected)
                {
                    clientSocket.Close();
                }
            }
            catch
            {
                // 忽略关闭连接时可能发生的异常
            }
        }
    }
    //【4】处理JSON-RPC请求并执行命令
    private void ProcessRequest(Socket clientSocket, JsonRpcRequest request)
    {
        try
        {
            // 设置ExecCommandService的参数
            _execCommandService.CommandName = request.Method;
            _execCommandService.Parameters = request.Params != null ?
                Newtonsoft.Json.Linq.JObject.FromObject(request.Params) :
                new Newtonsoft.Json.Linq.JObject();
            _execCommandService.RequestId = request.Id;
            // 将客户端Socket存储到字典中，以便在命令执行完成后发送结果
            lock (_clientSockets)
            {
                if (_clientSockets.ContainsKey(request.Id))
                {
                    _clientSockets[request.Id] = clientSocket;
                }
                else
                {
                    _clientSockets.Add(request.Id, clientSocket);
                }
            }
            // 触发外部事件，执行命令
            _externalEvent.Raise();
            // 命令执行完成后会通过CommandExecuted事件回调发送响应
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "处理请求失败: {Method}", request.Method);
            SendErrorResponse(clientSocket, request.Id, -32603, $"处理请求失败: {ex.Message}");
        }
    }
    #region 响应结果处理
    // 发送成功响应
    private void SendSuccessResponse(Socket clientSocket, string id, object result)
    {
        var response = new JsonRpcResponse
        {
            Id = id,
            Result = result
        };
        SendResponse(clientSocket, response);
    }
    // 发送错误响应
    private void SendErrorResponse(Socket clientSocket, string id, int errorCode, string errorMessage, object? errorData = null)
    {
        var response = new JsonRpcResponse
        {
            Id = id
        };
        response.SetError(errorCode, errorMessage, errorData);
        SendResponse(clientSocket, response);
    }
    // 发送响应
    private void SendResponse(Socket clientSocket, JsonRpcResponse response)
    {
        try
        {
            // 检查Socket是否仍然连接
            if (clientSocket == null || !clientSocket.Connected)
            {
                _logger.LogWarning("无法发送响应，Socket已断开连接");
                return;
            }

            string jsonResponse = JsonConvert.SerializeObject(response);
            byte[] responseData = Encoding.UTF8.GetBytes(jsonResponse);
            // 发送数据长度
            byte[] lengthBytes = BitConverter.GetBytes(responseData.Length);
            clientSocket.Send(lengthBytes);
            // 发送实际数据
            clientSocket.Send(responseData);
            _logger.LogInformation("已发送响应: {JsonResponse}", jsonResponse);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "发送响应失败");
            // 发生异常时尝试关闭Socket
            try
            {
                if (clientSocket != null && clientSocket.Connected)
                {
                    clientSocket.Close();
                }
            }
            catch
            {
                // 忽略关闭Socket可能产生的异常
            }
        }
    }
    #endregion
    #region 外部事件回调
    // 命令执行完成事件处理方法
    private void OnCommandExecuted(string requestId, string result)
    {
        try
        {
            _logger.LogInformation("收到命令执行完成事件: RequestId={RequestId}, Result={Result}", requestId, result);
            // 从字典中获取对应的客户端Socket
            Socket? clientSocket = null;
            lock (_clientSockets)
            {
                if (_clientSockets.TryGetValue(requestId, out clientSocket))
                {
                    _clientSockets.Remove(requestId);
                }
            }
            // 如果找到对应的客户端Socket，发送执行结果
            if (clientSocket != null)
            {
                SendSuccessResponse(clientSocket, requestId, new
                {
                    status = "completed",
                    message = $"命令已执行完成",
                    result = result
                });
                
                // 发送响应后主动关闭Socket连接
                try
                {
                    if (clientSocket.Connected)
                    {
                        clientSocket.Shutdown(SocketShutdown.Both);
                        clientSocket.Close();
                    }
                }
                catch (Exception closeEx)
                {
                    _logger.LogError(closeEx, "关闭客户端Socket失败: RequestId={RequestId}", requestId);
                }
            }
            else
            {
                _logger.LogWarning("无法发送命令执行结果，客户端Socket已断开连接: RequestId={RequestId}", requestId);
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "处理命令执行完成事件失败: RequestId={RequestId}", requestId);
        }
    }
    #endregion
    #region 关闭Socket服务
    //停止Socket服务
    // 获取当前连接的客户端数量
    public int GetConnectedClientsCount()
    {
        lock (_clientSockets)
        {
            return _clientSockets.Count;
        }
    }

    public void Stop()
    {
        _isRunning = false;
        // 取消订阅事件
        _execCommandService.CommandExecuted -= OnCommandExecuted;
        // 关闭所有客户端连接
        lock (_clientSockets)
        {
            foreach (var socket in _clientSockets.Values)
            {
                try
                {
                    if (socket.Connected)
                    {
                        socket.Close();
                    }
                }
                catch (Exception ex)
                {
                    _logger.LogError(ex, "关闭客户端Socket连接失败");
                }
            }
            _clientSockets.Clear();
        }
        // 关闭服务器Socket
        if (_serverSocket != null)
        {
            try
            {
                _serverSocket.Close();
                _serverSocket.Dispose();
                _serverSocket = null;
                _logger.LogInformation("Socket服务器已停止");
            }
            catch (Exception ex)
            {
                _logger.LogError(ex, "停止Socket服务失败");
            }
        }
    }
    #endregion
}